﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using ActionSystem.Core;
using XMLib;

namespace ActionSystem.Camera
{
    /// <summary>
    /// 普通第三人视角
    /// </summary>
    [ActionConfig(typeof(ThirdAroundActionHandler))]
    public class ThirdAroundActionConfig : BaseStateActionConfig
    {
        [CustomLabel("碰撞检测")]
        public LayerMask obstructionLayers=-1;
        [CustomLabel("相机可调距离")]
        public Vector2 distanceRange = new Vector2(1,10f);
        [CustomLabel("Y偏移")]
        public float offsetUp = 0.8f;
        [CustomLabel("上下可调角度")]
        public Vector2 angeRange = new Vector2(-45, 60f);
        [CustomLabel("移动速度")]
        public float speed = 10;
        [CustomLabel("旋转速度")]
        public float rotateSpeed = 10;
        public override string ToString()
        {
            return $"{GetType().Name}";
        }
    }
    public class ThirdAroundActionHandler : BaseCameraHander
    {
        ThirdAroundActionConfig config;
        float baseSpeed = 0;
        float xAngle = 0;
        float yAngle = 0;
        float distance = 0;


        //碰撞检测相关
        private RaycastHit[] _obstructions = new RaycastHit[MaxObstructions];
        private Vector3 _currentFollowPosition;
        private const int MaxObstructions = 32;
        public float ObstructionCheckRadius = 0.2f;
        public LayerMask ObstructionLayers = -1;
        public float ObstructionSharpness = 10000f;




        public override void Enter(BaseStateAction action)
        {
            base.Enter(action);
            config = action.Config as ThirdAroundActionConfig;
            baseSpeed = config.speed / (1 + config.speed);//speed越大，速度越快

            xAngle = camera.transform.rotation.eulerAngles.x;//设置为当前角度
            yAngle = camera.transform.rotation.eulerAngles.y;
            distance = config.distanceRange.y;
            ObstructionLayers = config.obstructionLayers;
        }
        public override void Update(BaseStateAction action, float deltaTime)
        {
            //更新xangle,yangle
            xAngle += input.GetStickThisFrame(cameraMachine.StickKey).y * deltaTime * config.rotateSpeed;
            xAngle = Mathf.Clamp(xAngle, config.angeRange.x, config.angeRange.y);
            yAngle += input.GetStickThisFrame(cameraMachine.StickKey).x * deltaTime * config.rotateSpeed;
            //更新distance



            //更新相机位置和朝向
            Matrix4x4 m = Matrix4x4.Translate(follow.GetFallowPostion())*
                          Matrix4x4.Translate(follow.GetFallowUpDirection()*config.offsetUp)*
                          Matrix4x4.Rotate(Quaternion.Euler(xAngle,yAngle,0))*
                          Matrix4x4.Translate(Vector3.back * distance);
            var targetV4 = m*new Vector4(0,0,0,1);
            var targetposition = new Vector3(targetV4.x,targetV4.y,targetV4.z);
            var targetRotation = Quaternion.Euler(xAngle, yAngle, 0);
            

            //更新相机位置
            float t =  baseSpeed * action.State.Weight;
            targetposition = Vector3.Lerp(camera.transform.position, targetposition, t);
            //朝向
            camera.transform.rotation = Quaternion.Slerp(camera.transform.rotation, targetRotation, t);
            //camera.transform.position = targetposition;
            //防遮挡检测
            {
                _currentFollowPosition = follow.GetFallowPostion() + follow.GetFallowUpDirection() * config.offsetUp;
                RaycastHit closestHit = new RaycastHit();
                closestHit.distance = Mathf.Infinity;
                int _obstructionCount = Physics.SphereCastNonAlloc(_currentFollowPosition, ObstructionCheckRadius,
                    -camera.transform.forward, _obstructions, distance, ObstructionLayers, QueryTriggerInteraction.Ignore);
                for (int i = 0; i < _obstructionCount; i++)
                {
                    if (_obstructions[i].distance < closestHit.distance && _obstructions[i].distance > 0)
                    {
                        closestHit = _obstructions[i];
                    }
                }

                // If obstructions detecter
                float _currentDistance = distance;
                if (closestHit.distance < Mathf.Infinity)
                {
                    float hd = closestHit.distance - 0.25f;
                    if(hd<0)
                    {
                        hd = 0;
                    }
                    _currentDistance = Mathf.Lerp(_currentDistance, hd, 1 - Mathf.Exp(-ObstructionSharpness * deltaTime));
                    //最终位置
                    targetposition = _currentFollowPosition - ((targetRotation * Vector3.forward) * _currentDistance);
                }
                
                
            }            
            camera.transform.position = targetposition;             
        }

        public override void SetUpCameraInfo(BaseStateAction action, float deltaTime)
        {

            //更新ICameraInfo
            if (cameraMachine != null && cameraMachine.GetCamera() != null)
            {
                
                info?.SetMoveFarwrd(Vector3.Cross(cameraMachine.GetCamera().transform.right,follow.GetFallowUpDirection()));
                info?.SetMoveRight(cameraMachine.GetCamera().transform.right);
                info?.SetMoveUp(follow.GetFallowUpDirection());
            }
            else
            {
                info?.SetMoveFarwrd(Vector3.zero);
                info?.SetMoveRight(Vector3.zero);
                info?.SetMoveUp(Vector3.zero);
            }
        }
    }
}


